#!/bin/sh

revision="flash v0.3.7 (2023-07-23 by MIBonk & MIB-Wiki)"
# use --help for more info

export PATH=:/proc/boot:/sbin:/bin:/usr/bin:/usr/sbin:/net/mmx/bin:/net/mmx/usr/bin:/net/mmx/usr/sbin:/net/mmx/sbin:/net/mmx/mnt/app/armle/bin:/net/mmx/mnt/app/armle/sbin:/net/mmx/mnt/app/armle/usr/bin:/net/mmx/mnt/app/armle/usr/sbin
export LD_LIBRARY_PATH=/net/mmx/mnt/app/root/lib-target:/net/mmx/mnt/eso/lib:/net/mmx/eso/lib:/net/mmx/mnt/app/usr/lib:/net/mmx/mnt/app/armle/lib:/net/mmx/mnt/app/armle/lib/dll:/net/mmx/mnt/app/armle/usr/lib
export IPL_CONFIG_DIR=/etc/eso/production

thisname="$(basename $0)"
thisdir="$(dirname $0)"

if [ -z $LOG ]; then
	. $thisdir/../config/GLOBALS
	echo -ne "\n$ME-$thisname---->\n" >> $LOG
fi

if [ -f $TMP/$thisname.mib ] || [ -f $TMP/reboot.mib ]; then
	echo $thisname" or reboot is already running..."
	return 2> /dev/null
fi

MIBCAP=3
. $thisdir/../config/MIBCHECK

function IFSstage2 {
	if [ -f "$IFS2" ]; then
		[ -z "$GEM" ] && echo -ne "\033[33m"
		[ -z "$GEM" ] && echo -ne "\n"
		[ -z "$GEM" ] && echo -ne "\n"
		echo -ne "Do NOT power down the unit while flashing!\n"
		echo -ne "Do NOT remove the SD-card/USB stick!\n"
		[ -z "$GEM" ] && echo -ne "You have 10 seconds before flashing will start...\n"
		[ -z "$GEM" ] && echo -ne "\033[31m"
		[ -z "$GEM" ] && echo -ne "\nPress CTRL+C to abort!!!\n\n"
		[ -z "$GEM" ] && echo -ne "\033[00;00m"
		[ -z "$GEM" ] && echo -ne "10 seconds left..."
		COUNTER=9
		while [  $COUNTER -gt -1 ]; do
			sleep 1
			[ -z "$GEM" ] && echo -ne "$COUNTER..."
			let COUNTER=COUNTER-1
		done
		[ -z "$GEM" ] && echo -ne "\033[31m"
		[ -z "$GEM" ] && echo -ne "\n\n"
		echo -ne "Flashing will start now."
		[ -z "$GEM" ] && echo -ne "\n"
		echo -ne "\nDO NOT INTERRUPT!\n\nDURATION: ~3 Minutes\n"
		[ -z "$GEM" ] && echo -ne "\033[00;00m"
		echo -ne "\n" >> $LOG
		[ -f /net/rcc/usr/bin/flashlock ] && $FLASHUNLOCK >> $LOG
		[ -z "$GEM" ] && echo -ne "\n" | $TEE -i -a $LOG
		[ -z "$GEM" ] && echo -ne "\n" >> $LOG

		trap '' 2
		#TODO: case sensitive HEX ba vs BA has to be fixed for all
		#      Or delete this check completly, as offset is now determined very well from unit.
		if [[ "$OFFSETPART2" = "ba0000" ]] || [[ "$OFFSETPART2" = "BA0000" ]]; then
			echo -ne "Flashing on OFFSET 0x00"$OFFSETPART2"...\n\nThere will be no further output until flash is finished!\n" | $TEE -i -a $LOG
		elif [[ "$OFFSETPART2" = "c20000" ]] || [[ "$OFFSETPART2" = "C20000" ]]; then
			echo -ne "Flashing on OFFSET 0x00"$OFFSETPART2"...\n\nThere will be no further output until flash is finished!\n" | $TEE -i -a $LOG
		elif [[ "$OFFSETPART2" = "c00000" ]] || [[ "$OFFSETPART2" = "C00000" ]]; then
			echo -ne "Flashing on OFFSET 0x00"$OFFSETPART2"...\n\nThere will be no further output until flash is finished!\n" | $TEE -i -a $LOG
		elif [[ "$OFFSETPART2" = "be0000" ]] || [[ "$OFFSETPART2" = "BE0000" ]]; then
			echo -ne "Flashing on OFFSET 0x00"$OFFSETPART2"...\n\nThere will be no further output until flash is finished!\n" | $TEE -i -a $LOG
		elif [[ "$OFFSETPART2" = "bc0000" ]] || [[ "$OFFSETPART2" = "BC0000" ]]; then
			echo -ne "Flashing on OFFSET 0x00"$OFFSETPART2"...\n\nThere will be no further output until flash is finished!\n" | $TEE -i -a $LOG
		else
			echo -ne "\nFlash offset unknown, flashing aborted!\nGet in contact with M.I.B team and share your backup\nSupport will be added\n\n" | $TEE -i -a $LOG
			rm -rf $TMP/$thisname.mib 2>/dev/null
			exit 0
		fi

		FLASHLOG="/net/rcc/tmp/flash.log"
		echo "\n" > $FLASHLOG
		$FLASHIT -v -d -x -a $OFFSETPART2 -p /net/rcc/dev/fs0 -f $IFS2 >> $FLASHLOG
		cat $FLASHLOG >> $LOG #append $FLASHLOG to $LOG

		#validate flash
			STRING1="programming"
			STRING2="erasing"
			PROGRAMMING=$(grep -e $STRING1 $FLASHLOG 2> /dev/null | cut -b 54-177)
			#echo -ne "${#PROGRAMMING}\n"
			ERASING=$(grep -e $STRING2 $FLASHLOG 2> /dev/null | cut -b 54-177)
			#echo -ne "${#ERASING}\n"
			
		if [[ ${#PROGRAMMING} = ${#ERASING} ]]; then
			echo -ne "\nOK: Flash checked and valid\n" | $TEE -i -a $LOG
			sleep 2
		else
			echo -ne "\nATTENTION: Flash validation FAILED\n\nREBOOT will be CANCELED\n\n" | $TEE -i -a $LOG
			echo -ne "DO NOT reboot or power down  unit - read next lines carefully!!\n\n" | $TEE -i -a $LOG
			echo -ne "Possible reasons:\n1. Read error from SD\n2. SD card faulty\n3. File on SD corrupted\n\n"
			echo -ne "Actions:\n1. Copy patch file again to SD --> try to flash again\n   You can safely remove and insert SD now\n2. Still failing --> try with a FRESH SD card\n3. Still Failing --> get in contact with experts and share your log file\nAs long as you do not reboot or power down the unit the failed flash will not take effect.\nRecovery will be easier this way. However, even a rebooted unit can (most likely) be recovered with expert help and 20-50$ of hardware\n\n-- DO NOT PANIC - GET HELP --\n\n"
			echo -ne "You can go back now...\n"
			rm -rf $TMP/$thisname.mib 2>/dev/null
			exit 0
		fi

		trap 2

		[ -z "$GEM" ] && echo -ne "\n" | $TEE -i -a $LOG
		[ -f /net/rcc/usr/bin/flashlock ] && $FLASHLOCK >> $LOG
		[ -z "$GEM" ] && echo -ne "\n" | $TEE -i -a $LOG
		
	else
		echo -ne "\nNo Flashfiles there!\n\n" | $TEE -i -a $LOG
		echo -ne "Please check if unit is already patched.\n"
		echo -ne "Patch can only be applied to stock Firmware.\n\n"
		echo -ne "You can go back now...\n"
		rm -rf $TMP/$thisname.mib 2>/dev/null
		exit 0
	fi
	rm -rf $TMP/$thisname.mib 2>/dev/null

}

function DB_PARSER {
	# Parsing Patch with FEC and CP
	PATCH_DB="$VOLUME/patches/MHIG_patch_db.csv"
	IFS_VERSION=$(grep -E "RCC.*ifs-root.*App" $TMP/version.txt | awk -F "|" '{print $5}' | cut -c1-4 ) # get RCC ifs-root version
	#HW_VERSION=$(grep -E "RCC.*ifs-root.*App" $TMP/version.txt | awk -F "|" '{print $3}') # get RCC HW version
	OFFSETPART2_DB=$(grep -E $IFS_VERSION $PATCH_DB | awk -F ";" '{print $2}')
	STAGE2SIZE_orig=$(grep -E $IFS_VERSION $PATCH_DB | awk -F ";" '{print $3}')
	SHA1_orig=$(grep -E $IFS_VERSION $PATCH_DB | awk -F ";" '{print $4}')
	header_chk_FEC_CP=$(grep -E $IFS_VERSION $PATCH_DB | awk -F ";" '{print $5}')
	SHA1_FEC_CP=$(grep -E $IFS_VERSION $PATCH_DB | awk -F ";" '{print $6}')
	IFS2_new=$VOLUME"/patches/"$IFS_VERSION"-ifs-root-stage2-0x00"$OFFSETPART2"-"$header_chk_FEC_CP"_FEC_CP.ifs"
	IFS2_backup=$VOLUME"/backup/"$MUVERSION"-"$TRAINVERSION"-"$FAZIT"/"$MUVERSION"-ifs-root-part2-0x00"$OFFSETPART2".ifs"
}

function DEBUG {
	echo "--------------- DEBUG --------------" >> $LOG
	echo "IFS_VERSION:		"$IFS_VERSION >> $LOG
	echo "OFFSETPART2:		"$OFFSETPART2 >> $LOG
	echo "OFFSETPART2_DB:		"$OFFSETPART2_DB >> $LOG
	echo "STAGE2SIZE:		"$STAGE2SIZE >> $LOG
	echo "STAGE2SIZE_orig:	"$STAGE2SIZE_orig >> $LOG
	echo "SHA1_orig:		"$SHA1_orig >> $LOG
	echo "header_chk_FEC_CP:	"$header_chk_FEC_CP >> $LOG
	echo "SHA1_FEC_CP:		"$SHA1_FEC_CP >> $LOG
	echo "IFS2_new:		"$IFS2_new >> $LOG
	echo "IFS2_backup:		"$IFS2_backup >> $LOG
	echo "Big Endian:		${big_endian}" >> $LOG
	echo "SHA1_UNIT:		"$SHA1_UNIT >> $LOG
	echo "SHA1_PATCH:		"$SHA1_PATCH >> $LOG
	echo "------------------------------------" >> $LOG
}

function DDCALC {
	hex_value1="$OFFSETPART2" #start of stage2 in HEX
	hex_value2="$big_endian" # size of stage2 in HEX
	decimal_value1=$(echo "ibase=16; $hex_value1" | $BC) 2>> $LOG # 
	decimal_value2=$(echo "ibase=16; $hex_value2" | $BC) 2>> $LOG
	SKIPBLOCKS=$((decimal_value1 / 4096))
	COUNT=$(((decimal_value2 / 4096) + 1)) # count extended by 1 block to certainly get the end of stage2
}

function LITTLE2BIG {
	# Reverse the byte order
	big_endian=$(echo ${1} | sed 's/\(..\)\(..\)\(..\)\(..\)/\4\3\2\1/')
}

	case $1 in

	-p|-patch) {

		trap '' 2
			[ -n "$GEM" ] && touch $TMP/$thisname.mib

		 . $thisdir/backup -a
		echo -ne "Train: $TRAINVERSION\n"
		if [ ! -f $BACKUPFOLDER/$MUVERSION-EEProm.txt ] || [ ! -f $BACKUPFOLDER/$MUVERSION-RCC_fs0.bin ]; then
			echo -ne "\n" >> $LOG
			echo -ne "!!! Backup is not complete, it is not flash to continue with flash!\n\n" | $TEE -i -a $LOG
			echo -ne "\nYou can go back now...\n"
			rm -rf $TMP/$thisname.mib 2>/dev/null
			DEBUG
			exit 0
		fi

		IFS2=$VOLUME"/patches/"$TRAINVERSION"_"$MUVERSION"_PATCH/"$MUVERSION"-ifs-root-part2-0x00"$OFFSETPART2"-"$STAGE2SIZE".ifs" # patch folder and file
		PF=$VOLUME"/patches/"$TRAINVERSION"_"$MUVERSION"_PATCH" # patch folder

		echo -ne "\n" >> $LOG

		if [[ "$TRAINVERSION" = *MHIG* ]]; then
			if grep -E "RCC.*ifs-root.*App" $TMP/version.txt >/dev/null; then >> $LOG
				echo -ne "--- Reading patch DB...\n" | $TEE -i -a $LOG
				DB_PARSER
			else
				echo -ne "!!! Info about ifs-root partition is missing.\nPlease get in contact with M.I.B team and share your backup\n" | $TEE -i -a $LOG
				echo -ne "\nYou can go back now...\n"
				DEBUG
				exit 0
			fi
			echo -ne "--- Searching offset and size of root-stage2.ifs...:\n" | $TEE -i -a $LOG
			 . $thisdir/offset -log
			if [ $OFFSETPART2 = $OFFSETPART2_DB ]; then
				echo -ne "--- OK: OFFSETPART2 in DB and RCC flash match.\n" | $TEE -i -a $LOG
			else
				echo -ne "!!! Error: OFFSETPART2 in DB and RCC flash do NOT match.\n    Stopping here ...\n" | $TEE -i -a $LOG
				echo -ne "\nYou can go back now...\n"
				rm -rf $TMP/$thisname.mib 2>/dev/null
				DEBUG
				exit 0
			fi
			if [ $STAGE2SIZE = $STAGE2SIZE_orig ]; then
				echo -ne "--- OK: STAGE2SIZE in DB and RCC flash match.\n" | $TEE -i -a $LOG
			else
				echo -ne "!!! Error: STAGE2SIZE in DB and RCC flash do NOT match.\n" | $TEE -i -a $LOG
				if [ $STAGE2SIZE = $header_chk_FEC_CP ]; then
					echo -ne "!!! Patch is already installed\n" | $TEE -i -a $LOG
				fi
				echo -ne "    Stopping here ...\n" | $TEE -i -a $LOG
				rm -rf $TMP/$thisname.mib 2>/dev/null
				DEBUG
				exit 0
			fi
			echo -ne "--- Dumping root-stage2.ifs from RCC flash.\n" | $TEE -i -a $LOG
			echo -ne "    It will take about 1 minute. Please wait...\n" | $TEE -i -a $LOG
			LITTLE2BIG $STAGE2SIZE
			DDCALC
			STAGE2="$VOLUME/patches/$IFS_VERSION-ifs-root-stage2-0x00$OFFSETPART2-"$STAGE2SIZE"_check.ifs"
			#extract stage2 with correct length no FF at end of file.
			$DD bs=4096 skip=$SKIPBLOCKS if=$fs0p0 count=$COUNT | head -c $decimal_value2 > $STAGE2
			
			IFS2=$IFS2_new
			if [ ! -f $IFS2 ]; then
				echo -ne "--- Patching dumped root-stage2.ifs.\n" | $TEE -i -a $LOG
				top -i 1 | $TEE -i -a $LOG
				FreeRAM=$(top -i 1 | grep Memory: | $SED -n 's/.* \([0-9]\+\)M avail.*/\1/p')
				if [ $FreeRAM -lt 240 ]; then
					echo -ne "--- Free RAM on unit: "$FreeRAM"MB\n" | $TEE -i -a $LOG
					echo -ne "!!! Not enough RAM - Minimum required 240MB available\n   Patch can not be generated.\n!!! Reboot unit and try to run the patch again." | $TEE -i -a $LOG
					echo -ne "\nYou can go back now...\n"
					rm -rf $TMP/$thisname.mib 2>/dev/null
					DEBUG
					exit 0
				fi
				echo -ne "--- Free RAM on unit: "$FreeRAM"MB\n" | $TEE -i -a $LOG
				echo -ne "    It will take about 2 minutes. Please wait...\n" | $TEE -i -a $LOG
				$PATCHER -m ifs -v patch --pattern $VOLUME/mod/patch_pattern/patch_2_3_FEC_CP.pattern $STAGE2 | $TEE -i -a $LOG
				if [[ -f ${STAGE2%????}_patched.ifs ]]; then
					mv ${STAGE2%????}_patched.ifs $IFS2 2>> $LOG
				else
					echo -ne "!!! Patching failed.\n    Stopping here ...\n" | $TEE -i -a $LOG
					echo -ne "\nYou can go back now...\n"
					rm -rf $TMP/$thisname.mib 2>/dev/null
					DEBUG
					exit 0
				fi
			else
				echo -ne "--- OK: "$(basename $IFS2)" is created.\n" | $TEE -i -a $LOG
			fi
			echo -ne "--- Calculating SHA1 of $(basename $IFS2)\n" | $TEE -i -a $LOG
			SHA1_PATCH="$($SHA1 $IFS2 | awk '{print $1}')" 2>> $LOG
			if [[ $SHA1_PATCH = $SHA1_FEC_CP ]]; then
				echo -ne "--- OK: sha1 of $(basename $IFS2) is valid.\n" | $TEE -i -a $LOG
			else
				echo -ne "!!! sha1 of $(basename $IFS2) is NOT found in DB\n    Stopping here ...\n" | $TEE -i -a $LOG
				echo -ne "\nYou can go back now...\n"
				rm -rf $TMP/$thisname.mib 2>/dev/null
				DEBUG
				exit 0
			fi
			echo -ne "--- Calculating SHA1 of root-stage2.ifs in RCC flash.\n" | $TEE -i -a $LOG
			SHA1_UNIT="$($SHA1 $STAGE2 | awk '{print $1}')" 2>> $LOG
			rm -f $STAGE2
			if [[ $SHA1_UNIT = $SHA1_FEC_CP ]]; then 
				echo -ne "!!! root-stage2.ifs is already patched!\n    Stopping here ...\n" | $TEE -i -a $LOG
				echo -ne "\nYou can go back now...\n"
				rm -rf $TMP/$thisname.mib 2>/dev/null
				DEBUG
				exit 0
			elif [[ $SHA1_UNIT = $SHA1_orig ]]; then 
				echo -ne "--- root-stage2.ifs in RCC flash is stock.\n" | $TEE -i -a $LOG
				echo -ne "    Replacing with $(basename $IFS2)...\n" | $TEE -i -a $LOG
			else
				echo -ne "!!! root-stage2.ifs in RCC flash is unknown.\n    Stopping here ...\n" | $TEE -i -a $LOG
				echo -ne "\nYou can go back now...\n"
				rm -rf $TMP/$thisname.mib 2>/dev/null
				DEBUG
				exit 0
			fi
		elif [ ! -d $PF ]; then
			echo -ne "Patch folder "$PF" NOT found on SD card\n\n" | $TEE -i -a $LOG
			echo -ne "Possible reasons:\n1. Patch folder is not copied to SD\n2. FW is not yet known to M.I.B\n\n"
			echo -ne "Actions:\n1. Copy folder "$TRAINVERSION"_"$MUVERSION"_PATCH to SD card\n2. Share your backup in case no patch is available for this FW yet\n\n"
			echo -ne "Missing files/folders - no patch can be applied\n\n"
			echo -ne "You can go back now...\n"
			rm -rf $TMP/$thisname.mib 2>/dev/null
			DEBUG
			exit 0
		else
			echo -ne "OK: Patch folder "$PF" found on SD card\n\n" | $TEE -i -a $LOG
			if [ -f $IFS2 ]; then
				echo -ne "OK: File "$MUVERSION-ifs-root-part2-0x00$OFFSETPART2-$STAGE2SIZE.ifs" found in folder\n\n" | $TEE -i -a $LOG
				sleep 2
			else
				STAGE2SIZE_STOCK=$(find $PF -name $MUVERSION"*.ifs" 2> /dev/null | cut -b 92-99) # Stock ifs-root-stage2 header size
				STAGE2FILE_SD=$(find $PF -name $MUVERSION"*.ifs" -type f -printf "%f\n") # Stock ifs-root-stage2 file name
				STAGE2FILE_SD_PATH=$(find $PF -name $MUVERSION"*.ifs") # Stock ifs-root-stage2 file name with path
				# /net/mmx/fs/sda0/patches/MHI2_ER_SKG13_P4526_MU1440_PATCH/MU1440-ifs-root-part2-0x00ba0000-1C06F300.ifs
				STAGE2SIZE_PATCH=$(dd bs=4 skip=9 count=1 if=$STAGE2FILE_SD_PATH 2> /dev/null | $XXD -u -ps) # Patched ifs-root-stage2 header size
				echo -ne "File "$STAGE2FILE_SD" found in patch folder\n" | $TEE -i -a $LOG
				echo -ne "File "$MUVERSION-ifs-root-part2-0x00$OFFSETPART2-$STAGE2SIZE.ifs" nedded to patch this unit\n" | $TEE -i -a $LOG
				if [[ $STAGE2SIZE_PATCH = $STAGE2SIZE ]]; then 
					echo -ne "\nUnit is already patched!\nHeader size on unit - $STAGE2SIZE - matches patch file - $STAGE2SIZE_PATCH -\n" | $TEE -i -a $LOG
					echo -ne "No need to patch unit again!\n\nYou can go back now...\n"
					rm -rf $TMP/$thisname.mib 2>/dev/null
					DEBUG
					exit 0
				else
					echo -ne "Header size on unit - $STAGE2SIZE - does not match patch files size - $STAGE2SIZE_PATCH - or stock - $STAGE2SIZE_STOCK - image\n\n" | $TEE -i -a $LOG
					echo -ne "Possible reasons:\n1. Unit holds an unknown patch! \n2. Wrong ifs-root-stage2 is flashed to unit\n3. Train/MU is not correct\n\n"
					echo -ne "Actions:\n1. Check train/MU\n2. Install FW again to get stock ifs-root-stage2 on unit\n\n"
					echo -ne "Patch can only be applied to stock Firmware.\n\n"
					echo -ne "You can go back now...\n"
					rm -rf $TMP/$thisname.mib 2>/dev/null
					DEBUG
					exit 0
				fi
			fi
		fi

		IFSstage2

		# TODO ifs-root-stage2 could be dumped after flash and compared against SHA1 of patch file
		#      rccd is only run if error occured, to document the failure
		. $thisdir/rccd -d #backup RCC after flash
		. $thisdir/fecel -fec #check for FECs and add new once if required
		[ $MIBMO = 1 ] && . $thisdir/fecel -el
		. $thisdir/showimage -load 30 $thisdir/../mod/images/showimage/ success.png
		. $thisdir/reboot -t 10

	trap 2

	return 2> /dev/null

	};;


	-r|-restore) {

	trap '' 2
			[ -n "$GEM" ] && touch $TMP/$thisname.mib

		. $thisdir/offset -log

		# flash back to Original...
		IFS2=$VOLUME"/backup/"$MUVERSION"-"$TRAINVERSION"-"$FAZIT"/"$MUVERSION"-ifs-root-part2-0x00"$OFFSETPART2".ifs"
		echo -ne "search "$FAZIT" Backup File "$MUVERSION"-ifs-root-part2-0x00"$OFFSETPART2".ifs\n" | $TEE -i -a $LOG

		IFSstage2

		. $thisdir/fecel -b
		. $thisdir/reboot -t 10

	trap 2

	return 2> /dev/null

	};;

	# help or unknown parameter ------------------------------
	*) {
		echo ""
		echo $revision
		echo ""
		echo "Usage: "$thisname" [OPTION]"
		echo ""
		echo "Options:"
		echo "        -p, -patch 		flash patch"
		echo "        -r, -restore 		flash original"
		echo "        --help			show this help"
		echo ""
		echo "Note: Flash will only work in RCC bash!"
		echo ""
		echo "This program is free software; you can redistribute it and/or"
		echo "modify it under the terms of the GNU General Public License"
		echo "as published by the Free Software Foundation; either version 2"
		echo "of the License, or (at your option) any later version."
		echo ""
		echo "This program is distributed in the hope that it will be useful,"
		echo "but WITHOUT ANY WARRANTY; without even the implied warranty of"
		echo "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
		echo "See the GNU General Public License for more details."
		echo ""
		echo "You should have received a copy of the GNU General Public License"
		echo "along with this program; if not, write to the Free Software Foundation,"
		echo "Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA."
		echo ""

	};;

	esac

exit 0
